package net.minecraft.world.storage.loot.functions;

import com.google.common.collect.Maps;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonSyntaxException;

import java.lang.reflect.Type;
import java.util.Map;

import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.conditions.LootCondition;

public class LootFunctionManager {
    private static final Map<ResourceLocation, LootFunction.Serializer<?>> NAME_TO_SERIALIZER_MAP = Maps.<ResourceLocation, LootFunction.Serializer<?>>newHashMap();
    private static final Map<Class<? extends LootFunction>, LootFunction.Serializer<?>> CLASS_TO_SERIALIZER_MAP = Maps.<Class<? extends LootFunction>, LootFunction.Serializer<?>>newHashMap();

    public static <T extends LootFunction> void registerFunction(LootFunction.Serializer<? extends T> serializer) {
        ResourceLocation resourcelocation = serializer.getFunctionName();
        Class<T> oclass = (Class<T>) serializer.getFunctionClass();

        if (NAME_TO_SERIALIZER_MAP.containsKey(resourcelocation)) {
            throw new IllegalArgumentException("Can't re-register item function name " + resourcelocation);
        } else if (CLASS_TO_SERIALIZER_MAP.containsKey(oclass)) {
            throw new IllegalArgumentException("Can't re-register item function class " + oclass.getName());
        } else {
            NAME_TO_SERIALIZER_MAP.put(resourcelocation, serializer);
            CLASS_TO_SERIALIZER_MAP.put(oclass, serializer);
        }
    }

    public static LootFunction.Serializer<?> getSerializerForName(ResourceLocation location) {
        LootFunction.Serializer<?> serializer = (LootFunction.Serializer) NAME_TO_SERIALIZER_MAP.get(location);

        if (serializer == null) {
            throw new IllegalArgumentException("Unknown loot item function '" + location + "'");
        } else {
            return serializer;
        }
    }

    public static <T extends LootFunction> LootFunction.Serializer<T> getSerializerFor(T functionClass) {
        LootFunction.Serializer<T> serializer = (LootFunction.Serializer) CLASS_TO_SERIALIZER_MAP.get(functionClass.getClass());

        if (serializer == null) {
            throw new IllegalArgumentException("Unknown loot item function " + functionClass);
        } else {
            return serializer;
        }
    }

    static {
        registerFunction(new SetCount.Serializer());
        registerFunction(new SetMetadata.Serializer());
        registerFunction(new EnchantWithLevels.Serializer());
        registerFunction(new EnchantRandomly.Serializer());
        registerFunction(new SetNBT.Serializer());
        registerFunction(new Smelt.Serializer());
        registerFunction(new LootingEnchantBonus.Serializer());
        registerFunction(new SetDamage.Serializer());
        registerFunction(new SetAttributes.Serializer());
    }

    public static class Serializer implements JsonDeserializer<LootFunction>, JsonSerializer<LootFunction> {
        public LootFunction deserialize(JsonElement p_deserialize_1_, Type p_deserialize_2_, JsonDeserializationContext p_deserialize_3_) throws JsonParseException {
            JsonObject jsonobject = JsonUtils.getJsonObject(p_deserialize_1_, "function");
            ResourceLocation resourcelocation = new ResourceLocation(JsonUtils.getString(jsonobject, "function"));
            LootFunction.Serializer<?> serializer;

            try {
                serializer = LootFunctionManager.getSerializerForName(resourcelocation);
            } catch (IllegalArgumentException var8) {
                throw new JsonSyntaxException("Unknown function '" + resourcelocation + "'");
            }

            return serializer.deserialize(jsonobject, p_deserialize_3_, (LootCondition[]) JsonUtils.deserializeClass(jsonobject, "conditions", new LootCondition[0], p_deserialize_3_, LootCondition[].class));
        }

        public JsonElement serialize(LootFunction p_serialize_1_, Type p_serialize_2_, JsonSerializationContext p_serialize_3_) {
            LootFunction.Serializer<LootFunction> serializer = LootFunctionManager.<LootFunction>getSerializerFor(p_serialize_1_);
            JsonObject jsonobject = new JsonObject();
            serializer.serialize(jsonobject, p_serialize_1_, p_serialize_3_);
            jsonobject.addProperty("function", serializer.getFunctionName().toString());

            if (p_serialize_1_.getConditions() != null && p_serialize_1_.getConditions().length > 0) {
                jsonobject.add("conditions", p_serialize_3_.serialize(p_serialize_1_.getConditions()));
            }

            return jsonobject;
        }
    }
}